输出5*5棋盘的骑士周游的方法数:
#include<stdio.h>
#include<stdlib.h>
#define X 5
#define Y 5
int chess[X][Y]={{0}};//二维数组的初始化,两个大括号
int count=0;
void print()
{
int i,j;
for(i=0;i<X;++i)
{
for(j=0;j<Y;++j)
{
printf("%d ",chess[i][j]);
}
printf("\n");//这里的\n放置也非常巧妙,一行之后换行
}
printf("\n");//一趟走完也换一次行,亲测这个没必要换行,因为visit中已经有换行;用了也没事,就多一个换行而已
}
void visit(int x,int y,int tag)
{
int i,j;
i=x;
j=y;
chess[i][j]=tag;
if(tag==X*Y)
{
printf("第%d方法:\n",++count);//这里有一个换行不要忘记了
print();
}
/*
1、一只在中间的马,假如四周都可以走,那么他有八种走法;每个象限各两种;
2、用回溯法,每次递归哪个位置是随机的,取决于你安排的if的位置前后
3、有一个递归变量tag每次递增1,是用来判断当tag等于棋盘大小时,则算一次走完全盘
4、这里有个count全局变量也非常重要,是用来记录总共有多少个走法;
仔细体会体会count和tag的不同之处,都是递归加1,但是做法和作用不太一样
5、还有这里的X,Y也是属于全局变量,要注意理解
6、横纵坐标的问题,这里的数组象限判断出错了,i正负,表示上下移动,即行方向移动,不要和数学中的混淆;
j正负,表示左右移动,即列方向移动,
*/
//第一象限右一进二 第一象限进一右二
if(i+1<X&&j+2<Y&&chess[i+1][j+2]==0)
{
visit(i+1,j+2,tag+1);
}
//第一象限右二进一 第一象限进二右一
if(i+2<X&&j+1<Y&&chess[i+2][j+1]==0)
{
visit(i+2,j+1,tag+1);
}
//第二象限左一进二 第四象限退一右二
if(i-1>=0&&j+2<Y&&chess[i-1][j+2]==0)
{
visit(i-1,j+2,tag+1);
}
//第二象限左二进一 第四象限退二右一
if(i-2>=0&&j+1<Y&&chess[i-2][j+1]==0)
{
visit(i-2,j+1,tag+1);
}
//第三象限左一退二 第三象限退一左二
if(i-1>=0&&j-2>=0&&chess[i-1][j-2]==0)
{
visit(i-1,j-2,tag+1);
}
//第三象限左二退一 第三象限退二左一
if(i-2>=0&&j-1>=0&&chess[i-2][j-1]==0)
{
visit(i-2,j-1,tag+1);
}
//第四象限右一退二 第二象限进一左二
if(i+1<X&&j-2>=0&&chess[i+1][j-2]==0)
{
visit(i+1,j-2,tag+1);
}
//第四象限右二退一 第二象限进二左一
if(i+2<X&&j-1>=0&&chess[i+2][j-1]==0)
{
visit(i+2,j-1,tag+1);
}
/*这一步重置标记位置为0,也是相当重要,作用是让给下一种走法;
这个chess放在这里很巧妙,可能有点难理解:chess是放在所有八个递归函数的最后,也就是说,第一次
执行这个chess是第一个tag=X*Y,比如5*5就是25;然后从25开始,依次回退,
这里还有一个难点,就是这里是回溯法,所以更准确的说不是,从25开始依次回退到1;而是从25回退,让后再检测其他相邻结点;
有点像深度优先查询;
*/
chess[i][j]=0;
}
int main()
{
int n,l;
printf("请输入棋盘的第一个落子位置坐标,空格分隔,横纵坐标都已0开始:");
scanf("%d %d",&n,&l);
//visit第一个参数为纵坐标,第二个参数为横坐标,第三个参数固定为1,因为这是第一次调用,横纵坐标从左上角0,0开始
visit(n,l,1);
return 0;
}